home *** CD-ROM | disk | FTP | other *** search
/ Personal Computer World 2008 February / PCWFEB08.iso / Software / Resources / Developers / XAMPP 1.5.4 / Windows installer / xampp-win32-1.5.4-installer.exe / xampp / php / pear / Date / Calc.php next >
Encoding:
PHP Script  |  2005-12-02  |  64.2 KB  |  1,930 lines

  1. <?php
  2. /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
  3. //
  4. // +----------------------------------------------------------------------+
  5. // | Copyright (c) 1997-2005 Baba Buehler, Pierre-Alain Joye              |
  6. // +----------------------------------------------------------------------+
  7. // | This source file is subject to the New BSD license, That is bundled  |
  8. // | with this package in the file LICENSE, and is available through      |
  9. // | the world-wide-web at                                                |
  10. // | http://www.opensource.org/licenses/bsd-license.php                   |
  11. // | If you did not receive a copy of the new BSDlicense and are unable   |
  12. // | to obtain it through the world-wide-web, please send a note to       |
  13. // | pear-dev@lists.php.net so we can mail you a copy immediately.        |
  14. // +----------------------------------------------------------------------+
  15. // | Author: Baba Buehler <baba@babaz.com>                                |
  16. // |         Pierre-Alain Joye <pajoye@php.net>                           |
  17. // +----------------------------------------------------------------------+
  18.  
  19. /**
  20.  * Calculates, manipulates and retrieves dates
  21.  *
  22.  * It does not rely on 32-bit system time stamps, so it works dates
  23.  * before 1970 and after 2038.
  24.  *
  25.  * PHP versions 4 and 5
  26.  *
  27.  * @category   Date and Time
  28.  * @package    Date
  29.  * @author     Monte Ohrt <monte@ispi.net>
  30.  * @author     Pierre-Alain Joye <pajoye@php.net>
  31.  * @author     Daniel Convissor <danielc@php.net>
  32.  * @copyright  1999-2005  Monte Ohrt, Pierre-Alain Joye, Daniel Convissor
  33.  * @license    http://www.opensource.org/licenses/bsd-license.php  New BSD License
  34.  * @version    CVS: $Id: Calc.php,v 1.33 2005/11/15 00:16:39 pajoye Exp $
  35.  * @link       http://pear.php.net/package/Date
  36.  * @since      File available since Release 1.2
  37.  */
  38.  
  39. if (!defined('DATE_CALC_BEGIN_WEEKDAY')) {
  40.     /**
  41.      * Defines what day starts the week
  42.      *
  43.      * Monday (1) is the international standard.
  44.      * Redefine this to 0 if you want weeks to begin on Sunday.
  45.      */
  46.     define('DATE_CALC_BEGIN_WEEKDAY', 1);
  47. }
  48.  
  49. if (!defined('DATE_CALC_FORMAT')) {
  50.     /**
  51.      * The default value for each method's $format parameter
  52.      *
  53.      * The default is '%Y%m%d'.  To override this default, define
  54.      * this constant before including Calc.php.
  55.      *
  56.      * @since Constant available since Release 1.5.0
  57.      */
  58.     define('DATE_CALC_FORMAT', '%Y%m%d');
  59. }
  60.  
  61. /**
  62.  * Calculates, manipulates and retrieves dates
  63.  *
  64.  * It does not rely on 32-bit system time stamps, so it works dates
  65.  * before 1970 and after 2038.
  66.  *
  67.  * @author     Monte Ohrt <monte@ispi.net>
  68.  * @author     Daniel Convissor <danielc@php.net>
  69.  * @copyright  1999, 2002, 2003 ispi
  70.  * @license    http://www.opensource.org/licenses/bsd-license.php  New BSD License
  71.  * @version    Release: 1.4.6
  72.  * @link       http://pear.php.net/package/Date
  73.  * @since      Class available since Release 1.2
  74.  */
  75. class Date_Calc
  76. {
  77.     /**
  78.      * Formats the date in the given format, much like strfmt()
  79.      *
  80.      * This function is used to alleviate the problem with 32-bit numbers for
  81.      * dates pre 1970 or post 2038, as strfmt() has on most systems.
  82.      * Most of the formatting options are compatible.
  83.      *
  84.      * Formatting options:
  85.      * <pre>
  86.      * %a   abbreviated weekday name (Sun, Mon, Tue)
  87.      * %A   full weekday name (Sunday, Monday, Tuesday)
  88.      * %b   abbreviated month name (Jan, Feb, Mar)
  89.      * %B   full month name (January, February, March)
  90.      * %d   day of month (range 00 to 31)
  91.      * %e   day of month, single digit (range 0 to 31)
  92.      * %E   number of days since unspecified epoch (integer)
  93.      *        (%E is useful for passing a date in a URL as
  94.      *        an integer value. Then simply use
  95.      *        daysToDate() to convert back to a date.)
  96.      * %j   day of year (range 001 to 366)
  97.      * %m   month as decimal number (range 1 to 12)
  98.      * %n   newline character (\n)
  99.      * %t   tab character (\t)
  100.      * %w   weekday as decimal (0 = Sunday)
  101.      * %U   week number of current year, first sunday as first week
  102.      * %y   year as decimal (range 00 to 99)
  103.      * %Y   year as decimal including century (range 0000 to 9999)
  104.      * %%   literal '%'
  105.      * </pre>
  106.      *
  107.      * @param int    $day     the day of the month
  108.      * @param int    $month   the month
  109.      * @param int    $year    the year.  Use the complete year instead of the
  110.      *                         abbreviated version.  E.g. use 2005, not 05.
  111.      *                         Do not add leading 0's for years prior to 1000.
  112.      * @param string $format  the format string
  113.      *
  114.      * @return string  the date in the desired format
  115.      *
  116.      * @access public
  117.      * @static
  118.      */
  119.     function dateFormat($day, $month, $year, $format)
  120.     {
  121.         if (!Date_Calc::isValidDate($day, $month, $year)) {
  122.             $year  = Date_Calc::dateNow('%Y');
  123.             $month = Date_Calc::dateNow('%m');
  124.             $day   = Date_Calc::dateNow('%d');
  125.         }
  126.  
  127.         $output = '';
  128.  
  129.         for ($strpos = 0; $strpos < strlen($format); $strpos++) {
  130.             $char = substr($format, $strpos, 1);
  131.             if ($char == '%') {
  132.                 $nextchar = substr($format, $strpos + 1, 1);
  133.                 switch($nextchar) {
  134.                     case 'a':
  135.                         $output .= Date_Calc::getWeekdayAbbrname($day, $month, $year);
  136.                         break;
  137.                     case 'A':
  138.                         $output .= Date_Calc::getWeekdayFullname($day, $month, $year);
  139.                         break;
  140.                     case 'b':
  141.                         $output .= Date_Calc::getMonthAbbrname($month);
  142.                         break;
  143.                     case 'B':
  144.                         $output .= Date_Calc::getMonthFullname($month);
  145.                         break;
  146.                     case 'd':
  147.                         $output .= sprintf('%02d', $day);
  148.                         break;
  149.                     case 'e':
  150.                         $output .= $day;
  151.                         break;
  152.                     case 'E':
  153.                         $output .= Date_Calc::dateToDays($day, $month, $year);
  154.                         break;
  155.                     case 'j':
  156.                         $output .= Date_Calc::julianDate($day, $month, $year);
  157.                         break;
  158.                     case 'm':
  159.                         $output .= sprintf('%02d', $month);
  160.                         break;
  161.                     case 'n':
  162.                         $output .= "\n";
  163.                         break;
  164.                     case 't':
  165.                         $output .= "\t";
  166.                         break;
  167.                     case 'w':
  168.                         $output .= Date_Calc::dayOfWeek($day, $month, $year);
  169.                         break;
  170.                     case 'U':
  171.                         $output .= Date_Calc::weekOfYear($day, $month, $year);
  172.                         break;
  173.                     case 'y':
  174.                         $output .= substr($year, 2, 2);
  175.                         break;
  176.                     case 'Y':
  177.                         $output .= $year;
  178.                         break;
  179.                     case '%':
  180.                         $output .= '%';
  181.                         break;
  182.                     default:
  183.                         $output .= $char.$nextchar;
  184.                 }
  185.                 $strpos++;
  186.             } else {
  187.                 $output .= $char;
  188.             }
  189.         }
  190.         return $output;
  191.     }
  192.  
  193.     /**
  194.      * Turns a two digit year into a four digit year
  195.      *
  196.      * From '51 to '99 is in the 1900's, otherwise it's in the 2000's.
  197.      *
  198.      * @param int    $year    the 2 digit year
  199.      *
  200.      * @return string  the 4 digit year
  201.      *
  202.      * @access public
  203.      * @static
  204.      */
  205.     function defaultCentury($year)
  206.     {
  207.         if (strlen($year) == 1) {
  208.             $year = '0' . $year;
  209.         }
  210.         if ($year > 50) {
  211.             return '19' . $year;
  212.         } else {
  213.             return '20' . $year;
  214.         }
  215.     }
  216.  
  217.     /**
  218.      * Converts a date to number of days since a distant unspecified epoch
  219.      *
  220.      * @param int    $day     the day of the month
  221.      * @param int    $month   the month
  222.      * @param int    $year    the year.  Use the complete year instead of the
  223.      *                         abbreviated version.  E.g. use 2005, not 05.
  224.      *                         Do not add leading 0's for years prior to 1000.
  225.      *
  226.      * @return integer  the number of days since the Date_Calc epoch
  227.      *
  228.      * @access public
  229.      * @static
  230.      */
  231.     function dateToDays($day, $month, $year)
  232.     {
  233.         $century = (int)substr($year, 0, 2);
  234.         $year = (int)substr($year, 2, 2);
  235.         if ($month > 2) {
  236.             $month -= 3;
  237.         } else {
  238.             $month += 9;
  239.             if ($year) {
  240.                 $year--;
  241.             } else {
  242.                 $year = 99;
  243.                 $century --;
  244.             }
  245.         }
  246.  
  247.         return (floor((146097 * $century) / 4 ) +
  248.                 floor((1461 * $year) / 4 ) +
  249.                 floor((153 * $month + 2) / 5 ) +
  250.                 $day + 1721119);
  251.     }
  252.  
  253.     /**
  254.      * Converts number of days to a distant unspecified epoch
  255.      *
  256.      * @param int    $days    the number of days since the Date_Calc epoch
  257.      * @param string $format  the string indicating how to format the output
  258.      *
  259.      * @return string  the date in the desired format
  260.      *
  261.      * @access public
  262.      * @static
  263.      */
  264.     function daysToDate($days, $format = DATE_CALC_FORMAT)
  265.     {
  266.         $days   -= 1721119;
  267.         $century = floor((4 * $days - 1) / 146097);
  268.         $days    = floor(4 * $days - 1 - 146097 * $century);
  269.         $day     = floor($days / 4);
  270.  
  271.         $year    = floor((4 * $day +  3) / 1461);
  272.         $day     = floor(4 * $day +  3 - 1461 * $year);
  273.         $day     = floor(($day +  4) / 4);
  274.  
  275.         $month   = floor((5 * $day - 3) / 153);
  276.         $day     = floor(5 * $day - 3 - 153 * $month);
  277.         $day     = floor(($day +  5) /  5);
  278.  
  279.         if ($month < 10) {
  280.             $month +=3;
  281.         } else {
  282.             $month -=9;
  283.             if ($year++ == 99) {
  284.                 $year = 0;
  285.                 $century++;
  286.             }
  287.         }
  288.  
  289.         $century = sprintf('%02d', $century);
  290.         $year    = sprintf('%02d', $year);
  291.         return Date_Calc::dateFormat($day, $month, $century . $year, $format);
  292.     }
  293.  
  294.     /**
  295.      * Converts from Gregorian Year-Month-Day to ISO Year-WeekNumber-WeekDay
  296.      *
  297.      * Uses ISO 8601 definitions.  Algorithm by Rick McCarty, 1999 at
  298.      * http://personal.ecu.edu/mccartyr/ISOwdALG.txt .
  299.      * Transcribed to PHP by Jesus M. Castagnetto.
  300.      *
  301.      * @param int    $day     the day of the month
  302.      * @param int    $month   the month
  303.      * @param int    $year    the year.  Use the complete year instead of the
  304.      *                         abbreviated version.  E.g. use 2005, not 05.
  305.      *                         Do not add leading 0's for years prior to 1000.
  306.      *
  307.      * @return string  the date in ISO Year-WeekNumber-WeekDay format
  308.      *
  309.      * @access public
  310.      * @static
  311.      */
  312.     function gregorianToISO($day, $month, $year) {
  313.         $mnth = array (0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334);
  314.         $y_isleap = Date_Calc::isLeapYear($year);
  315.         $y_1_isleap = Date_Calc::isLeapYear($year - 1);
  316.         $day_of_year_number = $day + $mnth[$month - 1];
  317.         if ($y_isleap && $month > 2) {
  318.             $day_of_year_number++;
  319.         }
  320.         // find Jan 1 weekday (monday = 1, sunday = 7)
  321.         $yy = ($year - 1) % 100;
  322.         $c = ($year - 1) - $yy;
  323.         $g = $yy + intval($yy / 4);
  324.         $jan1_weekday = 1 + intval((((($c / 100) % 4) * 5) + $g) % 7);
  325.         // weekday for year-month-day
  326.         $h = $day_of_year_number + ($jan1_weekday - 1);
  327.         $weekday = 1 + intval(($h - 1) % 7);
  328.         // find if Y M D falls in YearNumber Y-1, WeekNumber 52 or
  329.         if ($day_of_year_number <= (8 - $jan1_weekday) && $jan1_weekday > 4){
  330.             $yearnumber = $year - 1;
  331.             if ($jan1_weekday == 5 || ($jan1_weekday == 6 && $y_1_isleap)) {
  332.                 $weeknumber = 53;
  333.             } else {
  334.                 $weeknumber = 52;
  335.             }
  336.         } else {
  337.             $yearnumber = $year;
  338.         }
  339.         // find if Y M D falls in YearNumber Y+1, WeekNumber 1
  340.         if ($yearnumber == $year) {
  341.             if ($y_isleap) {
  342.                 $i = 366;
  343.             } else {
  344.                 $i = 365;
  345.             }
  346.             if (($i - $day_of_year_number) < (4 - $weekday)) {
  347.                 $yearnumber++;
  348.                 $weeknumber = 1;
  349.             }
  350.         }
  351.         // find if Y M D falls in YearNumber Y, WeekNumber 1 through 53
  352.         if ($yearnumber == $year) {
  353.             $j = $day_of_year_number + (7 - $weekday) + ($jan1_weekday - 1);
  354.             $weeknumber = intval($j / 7);
  355.             if ($jan1_weekday > 4) {
  356.                 $weeknumber--;
  357.             }
  358.         }
  359.         // put it all together
  360.         if ($weeknumber < 10) {
  361.             $weeknumber = '0'.$weeknumber;
  362.         }
  363.         return $yearnumber . '-' . $weeknumber . '-' . $weekday;
  364.     }
  365.  
  366.     /**
  367.      * Determines julian date of the given season
  368.      *
  369.      * Adapted from previous work in Java by James Mark Hamilton.
  370.      *
  371.      * @param string $season  the season to get the date for: VERNALEQUINOX,
  372.      *                         SUMMERSOLSTICE, AUTUMNALEQUINOX,
  373.      *                         or WINTERSOLSTICE
  374.      * @param string $year    the year in four digit format.  Must be between
  375.      *                         -1000BC and 3000AD.
  376.      *
  377.      * @return float  the julian date the season starts on
  378.      *
  379.      * @author James Mark Hamilton <mhamilton@qwest.net>
  380.      * @author Robert Butler <rob@maxwellcreek.org>
  381.      * @access public
  382.      * @static
  383.      */
  384.     function dateSeason($season, $year = 0) {
  385.         if ($year == '') {
  386.             $year = Date_Calc::dateNow('%Y');
  387.         }
  388.         if (($year >= -1000) && ($year <= 1000)) {
  389.             $y = $year / 1000.0;
  390.             switch ($season) {
  391.                 case 'VERNALEQUINOX':
  392.                     $juliandate = (((((((-0.00071 * $y) - 0.00111) * $y) + 0.06134) * $y) + 365242.1374) * $y) + 1721139.29189;
  393.                     break;
  394.                 case 'SUMMERSOLSTICE':
  395.                     $juliandate = (((((((0.00025 * $y) + 0.00907) * $y) - 0.05323) * $y) + 365241.72562) * $y) + 1721233.25401;
  396.                     break;
  397.                 case 'AUTUMNALEQUINOX':
  398.                     $juliandate = (((((((0.00074 * $y) - 0.00297) * $y) - 0.11677) * $y) + 365242.49558) * $y) + 1721325.70455;
  399.                     break;
  400.                 case 'WINTERSOLSTICE':
  401.                 default:
  402.                     $juliandate = (((((((-0.00006 * $y) - 0.00933) * $y) - 0.00769) * $y) + 365242.88257) * $y) + 1721414.39987;
  403.             }
  404.         } elseif (($year > 1000) && ($year <= 3000)) {
  405.             $y = ($year - 2000) / 1000;
  406.             switch ($season) {
  407.                 case 'VERNALEQUINOX':
  408.                     $juliandate = (((((((-0.00057 * $y) - 0.00411) * $y) + 0.05169) * $y) + 365242.37404) * $y) + 2451623.80984;
  409.                     break;
  410.                 case 'SUMMERSOLSTICE':
  411.                     $juliandate = (((((((-0.0003 * $y) + 0.00888) * $y) + 0.00325) * $y) + 365241.62603) * $y) + 2451716.56767;
  412.                     break;
  413.                 case 'AUTUMNALEQUINOX':
  414.                     $juliandate = (((((((0.00078 * $y) + 0.00337) * $y) - 0.11575) * $y) + 365242.01767) * $y) + 2451810.21715;
  415.                     break;
  416.                 case 'WINTERSOLSTICE':
  417.                 default:
  418.                     $juliandate = (((((((0.00032 * $y) - 0.00823) * $y) - 0.06223) * $y) + 365242.74049) * $y) + 2451900.05952;
  419.             }
  420.         }
  421.         return $juliandate;
  422.     }
  423.  
  424.     /**
  425.      * Returns the current local date
  426.      *
  427.      * NOTE: This function retrieves the local date using strftime(),
  428.      * which may or may not be 32-bit safe on your system.
  429.      *
  430.      * @param string $format  the string indicating how to format the output
  431.      *
  432.      * @return string  the current date in the specified format
  433.      *
  434.      * @access public
  435.      * @static
  436.      */
  437.     function dateNow($format = DATE_CALC_FORMAT)
  438.     {
  439.         return strftime($format, time());
  440.     }
  441.  
  442.     /**
  443.      * Returns the current local year in format CCYY
  444.      *
  445.      * @return string  the current year in four digit format
  446.      *
  447.      * @access public
  448.      * @static
  449.      */
  450.     function getYear()
  451.     {
  452.         return Date_Calc::dateNow('%Y');
  453.     }
  454.  
  455.     /**
  456.      * Returns the current local month in format MM
  457.      *
  458.      * @return string  the current month in two digit format
  459.      *
  460.      * @access public
  461.      * @static
  462.      */
  463.     function getMonth()
  464.     {
  465.         return Date_Calc::dateNow('%m');
  466.     }
  467.  
  468.     /**
  469.      * Returns the current local day in format DD
  470.      *
  471.      * @return string  the current day of the month in two digit format
  472.      *
  473.      * @access public
  474.      * @static
  475.      */
  476.     function getDay()
  477.     {
  478.         return Date_Calc::dateNow('%d');
  479.     }
  480.  
  481.     /**
  482.      * Returns number of days since 31 December of year before given date
  483.      *
  484.      * @param int    $day     the day of the month, default is current local day
  485.      * @param int    $month   the month, default is current local month
  486.      * @param int    $year    the year in four digit format, default is current local year
  487.      *
  488.      * @return int  the julian date for the date
  489.      *
  490.      * @access public
  491.      * @static
  492.      */
  493.     function julianDate($day = 0, $month = 0, $year = 0)
  494.     {
  495.         if (empty($year)) {
  496.             $year = Date_Calc::dateNow('%Y');
  497.         }
  498.         if (empty($month)) {
  499.             $month = Date_Calc::dateNow('%m');
  500.         }
  501.         if (empty($day)) {
  502.             $day = Date_Calc::dateNow('%d');
  503.         }
  504.         $days = array(0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334);
  505.         $julian = ($days[$month - 1] + $day);
  506.         if ($month > 2 && Date_Calc::isLeapYear($year)) {
  507.             $julian++;
  508.         }
  509.         return $julian;
  510.     }
  511.  
  512.     /**
  513.      * Returns the full weekday name for the given date
  514.      *
  515.      * @param int    $day     the day of the month, default is current local day
  516.      * @param int    $month   the month, default is current local month
  517.      * @param int    $year    the year in four digit format, default is current local year
  518.      *
  519.      * @return string  the full name of the day of the week
  520.      *
  521.      * @access public
  522.      * @static
  523.      */
  524.     function getWeekdayFullname($day = 0, $month = 0, $year = 0)
  525.     {
  526.         if (empty($year)) {
  527.             $year = Date_Calc::dateNow('%Y');
  528.         }
  529.         if (empty($month)) {
  530.             $month = Date_Calc::dateNow('%m');
  531.         }
  532.         if (empty($day)) {
  533.             $day = Date_Calc::dateNow('%d');
  534.         }
  535.         $weekday_names = Date_Calc::getWeekDays();
  536.         $weekday = Date_Calc::dayOfWeek($day, $month, $year);
  537.         return $weekday_names[$weekday];
  538.     }
  539.  
  540.     /**
  541.      * Returns the abbreviated weekday name for the given date
  542.      *
  543.      * @param int    $day     the day of the month, default is current local day
  544.      * @param int    $month   the month, default is current local month
  545.      * @param int    $year    the year in four digit format, default is current local year
  546.      * @param int    $length  the length of abbreviation
  547.      *
  548.      * @return string  the abbreviated name of the day of the week
  549.      *
  550.      * @access public
  551.      * @static
  552.      * @see Date_Calc::getWeekdayFullname()
  553.      */
  554.     function getWeekdayAbbrname($day = 0, $month = 0, $year = 0, $length = 3)
  555.     {
  556.         if (empty($year)) {
  557.             $year = Date_Calc::dateNow('%Y');
  558.         }
  559.         if (empty($month)) {
  560.             $month = Date_Calc::dateNow('%m');
  561.         }
  562.         if (empty($day)) {
  563.             $day = Date_Calc::dateNow('%d');
  564.         }
  565.         return substr(Date_Calc::getWeekdayFullname($day, $month, $year),
  566.                       0, $length);
  567.     }
  568.  
  569.     /**
  570.      * Returns the full month name for the given month
  571.      *
  572.      * @param int    $month   the month
  573.      *
  574.      * @return string  the full name of the month
  575.      *
  576.      * @access public
  577.      * @static
  578.      */
  579.     function getMonthFullname($month)
  580.     {
  581.         $month = (int)$month;
  582.         if (empty($month)) {
  583.             $month = (int)Date_Calc::dateNow('%m');
  584.         }
  585.         $month_names = Date_Calc::getMonthNames();
  586.         return $month_names[$month];
  587.     }
  588.  
  589.     /**
  590.      * Returns the abbreviated month name for the given month
  591.      *
  592.      * @param int    $month   the month
  593.      * @param int    $length  the length of abbreviation
  594.      *
  595.      * @return string  the abbreviated name of the month
  596.      *
  597.      * @access public
  598.      * @static
  599.      * @see Date_Calc::getMonthFullname
  600.      */
  601.     function getMonthAbbrname($month, $length = 3)
  602.     {
  603.         $month = (int)$month;
  604.         if (empty($month)) {
  605.             $month = Date_Calc::dateNow('%m');
  606.         }
  607.         return substr(Date_Calc::getMonthFullname($month), 0, $length);
  608.     }
  609.  
  610.     /**
  611.      * Returns the numeric month from the month name or an abreviation
  612.      *
  613.      * Both August and Aug would return 8.
  614.      *
  615.      * @param string $month  the name of the month to examine.
  616.      *                        Case insensitive.
  617.      *
  618.      * @return integer  the month's number
  619.      *
  620.      * @access public
  621.      * @static
  622.      */
  623.     function getMonthFromFullName($month)
  624.     {
  625.         $month = strtolower($month);
  626.         $months = Date_Calc::getMonthNames();
  627.         while(list($id, $name) = each($months)) {
  628.             if (ereg($month, strtolower($name))) {
  629.                 return $id;
  630.             }
  631.         }
  632.         return 0;
  633.     }
  634.  
  635.     /**
  636.      * Returns an array of month names
  637.      *
  638.      * Used to take advantage of the setlocale function to return
  639.      * language specific month names.
  640.      *
  641.      * TODO: cache values to some global array to avoid preformace
  642.      * hits when called more than once.
  643.      *
  644.      * @returns array  an array of month names
  645.      *
  646.      * @access public
  647.      * @static
  648.      */
  649.     function getMonthNames()
  650.     {
  651.         for ($i = 1; $i < 13; $i++) {
  652.             $months[$i] = strftime('%B', mktime(0, 0, 0, $i, 1, 2001));
  653.         }
  654.         return $months;
  655.     }
  656.  
  657.     /**
  658.      * Returns an array of week days
  659.      *
  660.      * Used to take advantage of the setlocale function to
  661.      * return language specific week days.
  662.      *
  663.      * TODO: cache values to some global array to avoid preformace
  664.      * hits when called more than once.
  665.      *
  666.      * @returns array  an array of week day names
  667.      *
  668.      * @access public
  669.      * @static
  670.      */
  671.     function getWeekDays()
  672.     {
  673.         for ($i = 0; $i < 7; $i++) {
  674.             $weekdays[$i] = strftime('%A', mktime(0, 0, 0, 1, $i, 2001));
  675.         }
  676.         return $weekdays;
  677.     }
  678.  
  679.     /**
  680.      * Returns day of week for given date (0 = Sunday)
  681.      *
  682.      * @param int    $day     the day of the month, default is current local day
  683.      * @param int    $month   the month, default is current local month
  684.      * @param int    $year    the year in four digit format, default is current local year
  685.      *
  686.      * @return int  the number of the day in the week
  687.      *
  688.      * @access public
  689.      * @static
  690.      */
  691.     function dayOfWeek($day = 0, $month = 0, $year = 0)
  692.     {
  693.         if (empty($year)) {
  694.             $year = Date_Calc::dateNow('%Y');
  695.         }
  696.         if (empty($month)) {
  697.             $month = Date_Calc::dateNow('%m');
  698.         }
  699.         if (empty($day)) {
  700.             $day = Date_Calc::dateNow('%d');
  701.         }
  702.         if ($month > 2) {
  703.             $month -= 2;
  704.         } else {
  705.             $month += 10;
  706.             $year--;
  707.         }
  708.  
  709.         $day = (floor((13 * $month - 1) / 5) +
  710.                 $day + ($year % 100) +
  711.                 floor(($year % 100) / 4) +
  712.                 floor(($year / 100) / 4) - 2 *
  713.                 floor($year / 100) + 77);
  714.  
  715.         $weekday_number = $day - 7 * floor($day / 7);
  716.         return $weekday_number;
  717.     }
  718.  
  719.     /**
  720.      * Returns week of the year, first Sunday is first day of first week
  721.      *
  722.      * @param int    $day     the day of the month, default is current local day
  723.      * @param int    $month   the month, default is current local month
  724.      * @param int    $year    the year in four digit format, default is current local year
  725.      *
  726.      * @return int  the number of the week in the year
  727.      *
  728.      * @access public
  729.      * @static
  730.      */
  731.     function weekOfYear($day = 0, $month = 0, $year = 0)
  732.     {
  733.         if (empty($year)) {
  734.             $year = Date_Calc::dateNow('%Y');
  735.         }
  736.         if (empty($month)) {
  737.             $month = Date_Calc::dateNow('%m');
  738.         }
  739.         if (empty($day)) {
  740.             $day = Date_Calc::dateNow('%d');
  741.         }
  742.         $iso    = Date_Calc::gregorianToISO($day, $month, $year);
  743.         $parts  = explode('-', $iso);
  744.         $week_number = intval($parts[1]);
  745.         return $week_number;
  746.     }
  747.  
  748.     /**
  749.      * Returns quarter of the year for given date
  750.      *
  751.      * @param int    $day     the day of the month, default is current local day
  752.      * @param int    $month   the month, default is current local month
  753.      * @param int    $year    the year in four digit format, default is current local year
  754.      *
  755.      * @return int  the number of the quarter in the year
  756.      *
  757.      * @access public
  758.      * @static
  759.      */
  760.     function quarterOfYear($day = 0, $month = 0, $year = 0)
  761.     {
  762.         if (empty($year)) {
  763.             $year = Date_Calc::dateNow('%Y');
  764.         }
  765.         if (empty($month)) {
  766.             $month = Date_Calc::dateNow('%m');
  767.         }
  768.         if (empty($day)) {
  769.             $day = Date_Calc::dateNow('%d');
  770.         }
  771.         $year_quarter = intval(($month - 1) / 3 + 1);
  772.         return $year_quarter;
  773.     }
  774.  
  775.     /**
  776.      * Find the number of days in the given month
  777.      *
  778.      * @param int    $month   the month, default is current local month
  779.      * @param int    $year    the year in four digit format, default is current local year
  780.      *
  781.      * @return int  the number of days the month has
  782.      *
  783.      * @access public
  784.      * @static
  785.      */
  786.     function daysInMonth($month = 0, $year = 0)
  787.     {
  788.         if (empty($year)) {
  789.             $year = Date_Calc::dateNow('%Y');
  790.         }
  791.         if (empty($month)) {
  792.             $month = Date_Calc::dateNow('%m');
  793.         }
  794.  
  795.         if ($year == 1582 && $month == 10) {
  796.             return 21;  // October 1582 only had 1st-4th and 15th-31st
  797.         }
  798.  
  799.         if ($month == 2) {
  800.             if (Date_Calc::isLeapYear($year)) {
  801.                 return 29;
  802.              } else {
  803.                 return 28;
  804.             }
  805.         } elseif ($month == 4 or $month == 6 or $month == 9 or $month == 11) {
  806.             return 30;
  807.         } else {
  808.             return 31;
  809.         }
  810.     }
  811.  
  812.     /**
  813.      * Returns the number of rows on a calendar month
  814.      *
  815.      * Useful for determining the number of rows when displaying a typical
  816.      * month calendar.
  817.      *
  818.      * @param int    $month   the month, default is current local month
  819.      * @param int    $year    the year in four digit format, default is current local year
  820.      *
  821.      * @return int  the number of weeks the month has
  822.      *
  823.      * @access public
  824.      * @static
  825.      */
  826.     function weeksInMonth($month = 0, $year = 0)
  827.     {
  828.         if (empty($year)) {
  829.             $year = Date_Calc::dateNow('%Y');
  830.         }
  831.         if (empty($month)) {
  832.             $month = Date_Calc::dateNow('%m');
  833.         }
  834.         $FDOM = Date_Calc::firstOfMonthWeekday($month, $year);
  835.         if (DATE_CALC_BEGIN_WEEKDAY==1 && $FDOM==0) {
  836.             $first_week_days = 7 - $FDOM + DATE_CALC_BEGIN_WEEKDAY;
  837.             $weeks = 1;
  838.         } elseif (DATE_CALC_BEGIN_WEEKDAY==0 && $FDOM == 6) {
  839.             $first_week_days = 7 - $FDOM + DATE_CALC_BEGIN_WEEKDAY;
  840.             $weeks = 1;
  841.         } else {
  842.             $first_week_days = DATE_CALC_BEGIN_WEEKDAY - $FDOM;
  843.             $weeks = 0;
  844.         }
  845.         $first_week_days %= 7;
  846.         return ceil((Date_Calc::daysInMonth($month, $year)
  847.                      - $first_week_days) / 7) + $weeks;
  848.     }
  849.  
  850.     /**
  851.      * Return an array with days in week
  852.      *
  853.      * @param int    $day     the day of the month, default is current local day
  854.      * @param int    $month   the month, default is current local month
  855.      * @param int    $year    the year in four digit format, default is current local year
  856.      * @param string $format  the string indicating how to format the output
  857.      *
  858.      * @return array $week[$weekday]
  859.      *
  860.      * @access public
  861.      * @static
  862.      */
  863.     function getCalendarWeek($day = 0, $month = 0, $year = 0,
  864.                              $format = DATE_CALC_FORMAT)
  865.     {
  866.         if (empty($year)) {
  867.             $year = Date_Calc::dateNow('%Y');
  868.         }
  869.         if (empty($month)) {
  870.             $month = Date_Calc::dateNow('%m');
  871.         }
  872.         if (empty($day)) {
  873.             $day = Date_Calc::dateNow('%d');
  874.         }
  875.  
  876.         $week_array = array();
  877.  
  878.         // date for the column of week
  879.  
  880.         $curr_day = Date_Calc::beginOfWeek($day, $month, $year,'%E');
  881.  
  882.         for ($counter = 0; $counter <= 6; $counter++) {
  883.             $week_array[$counter] = Date_Calc::daysToDate($curr_day, $format);
  884.             $curr_day++;
  885.         }
  886.         return $week_array;
  887.     }
  888.  
  889.     /**
  890.      * Return a set of arrays to construct a calendar month for the given date
  891.      *
  892.      * @param int    $month   the month, default is current local month
  893.      * @param int    $year    the year in four digit format, default is current local year
  894.      * @param string $format  the string indicating how to format the output
  895.      *
  896.      * @return array $month[$row][$col]
  897.      *
  898.      * @access public
  899.      * @static
  900.      */
  901.     function getCalendarMonth($month = 0, $year = 0,
  902.                               $format = DATE_CALC_FORMAT)
  903.     {
  904.         if (empty($year)) {
  905.             $year = Date_Calc::dateNow('%Y');
  906.         }
  907.         if (empty($month)) {
  908.             $month = Date_Calc::dateNow('%m');
  909.         }
  910.  
  911.         $month_array = array();
  912.  
  913.         // date for the first row, first column of calendar month
  914.         if (DATE_CALC_BEGIN_WEEKDAY == 1) {
  915.             if (Date_Calc::firstOfMonthWeekday($month, $year) == 0) {
  916.                 $curr_day = Date_Calc::dateToDays('01', $month, $year) - 6;
  917.             } else {
  918.                 $curr_day = Date_Calc::dateToDays('01', $month, $year)
  919.                     - Date_Calc::firstOfMonthWeekday($month, $year) + 1;
  920.             }
  921.         } else {
  922.             $curr_day = (Date_Calc::dateToDays('01', $month, $year)
  923.                 - Date_Calc::firstOfMonthWeekday($month, $year));
  924.         }
  925.  
  926.         // number of days in this month
  927.         $daysInMonth = Date_Calc::daysInMonth($month, $year);
  928.  
  929.         $weeksInMonth = Date_Calc::weeksInMonth($month, $year);
  930.         for ($row_counter = 0; $row_counter < $weeksInMonth; $row_counter++) {
  931.             for ($column_counter = 0; $column_counter <= 6; $column_counter++) {
  932.                 $month_array[$row_counter][$column_counter] =
  933.                         Date_Calc::daysToDate($curr_day , $format);
  934.                 $curr_day++;
  935.             }
  936.         }
  937.  
  938.         return $month_array;
  939.     }
  940.  
  941.     /**
  942.      * Return a set of arrays to construct a calendar year for the given date
  943.      *
  944.      * @param int    $year    the year in four digit format, default current local year
  945.      * @param string $format  the string indicating how to format the output
  946.      *
  947.      * @return array $year[$month][$row][$col]
  948.      *
  949.      * @access public
  950.      * @static
  951.      */
  952.     function getCalendarYear($year = 0, $format = DATE_CALC_FORMAT)
  953.     {
  954.         if (empty($year)) {
  955.             $year = Date_Calc::dateNow('%Y');
  956.         }
  957.  
  958.         $year_array = array();
  959.  
  960.         for ($curr_month = 0; $curr_month <= 11; $curr_month++) {
  961.             $year_array[$curr_month] =
  962.                     Date_Calc::getCalendarMonth($curr_month + 1,
  963.                                                 $year, $format);
  964.         }
  965.  
  966.         return $year_array;
  967.     }
  968.  
  969.     /**
  970.      * Returns date of day before given date
  971.      *
  972.      * @param int    $day     the day of the month, default is current local day
  973.      * @param int    $month   the month, default is current local month
  974.      * @param int    $year    the year in four digit format, default is current local year
  975.      * @param string $format  the string indicating how to format the output
  976.      *
  977.      * @return string  the date in the desired format
  978.      *
  979.      * @access public
  980.      * @static
  981.      */
  982.     function prevDay($day = 0, $month = 0, $year = 0,
  983.                      $format = DATE_CALC_FORMAT)
  984.     {
  985.         if (empty($year)) {
  986.             $year = Date_Calc::dateNow('%Y');
  987.         }
  988.         if (empty($month)) {
  989.             $month = Date_Calc::dateNow('%m');
  990.         }
  991.         if (empty($day)) {
  992.             $day = Date_Calc::dateNow('%d');
  993.         }
  994.         $days = Date_Calc::dateToDays($day, $month, $year);
  995.         return Date_Calc::daysToDate($days - 1, $format);
  996.     }
  997.  
  998.     /**
  999.      * Returns date of day after given date
  1000.      *
  1001.      * @param int    $day     the day of the month, default is current local day
  1002.      * @param int    $month   the month, default is current local month
  1003.      * @param int    $year    the year in four digit format, default is current local year
  1004.      * @param string $format  the string indicating how to format the output
  1005.      *
  1006.      * @return string  the date in the desired format
  1007.      *
  1008.      * @access public
  1009.      * @static
  1010.      */
  1011.     function nextDay($day = 0, $month = 0, $year = 0,
  1012.                      $format = DATE_CALC_FORMAT)
  1013.     {
  1014.         if (empty($year)) {
  1015.             $year = Date_Calc::dateNow('%Y');
  1016.         }
  1017.         if (empty($month)) {
  1018.             $month = Date_Calc::dateNow('%m');
  1019.         }
  1020.         if (empty($day)) {
  1021.             $day = Date_Calc::dateNow('%d');
  1022.         }
  1023.         $days = Date_Calc::dateToDays($day, $month, $year);
  1024.         return Date_Calc::daysToDate($days + 1, $format);
  1025.     }
  1026.  
  1027.     /**
  1028.      * Returns date of the previous weekday, skipping from Monday to Friday
  1029.      *
  1030.      * @param int    $day     the day of the month, default is current local day
  1031.      * @param int    $month   the month, default is current local month
  1032.      * @param int    $year    the year in four digit format, default is current local year
  1033.      * @param string $format  the string indicating how to format the output
  1034.      *
  1035.      * @return string  the date in the desired format
  1036.      *
  1037.      * @access public
  1038.      * @static
  1039.      */
  1040.     function prevWeekday($day = 0, $month = 0, $year = 0,
  1041.                          $format = DATE_CALC_FORMAT)
  1042.     {
  1043.         if (empty($year)) {
  1044.             $year = Date_Calc::dateNow('%Y');
  1045.         }
  1046.         if (empty($month)) {
  1047.             $month = Date_Calc::dateNow('%m');
  1048.         }
  1049.         if (empty($day)) {
  1050.             $day = Date_Calc::dateNow('%d');
  1051.         }
  1052.         $days = Date_Calc::dateToDays($day, $month, $year);
  1053.         if (Date_Calc::dayOfWeek($day, $month, $year) == 1) {
  1054.             $days -= 3;
  1055.         } elseif (Date_Calc::dayOfWeek($day, $month, $year) == 0) {
  1056.             $days -= 2;
  1057.         } else {
  1058.             $days -= 1;
  1059.         }
  1060.         return Date_Calc::daysToDate($days, $format);
  1061.     }
  1062.  
  1063.     /**
  1064.      * Returns date of the next weekday of given date, skipping from
  1065.      * Friday to Monday
  1066.      *
  1067.      * @param int    $day     the day of the month, default is current local day
  1068.      * @param int    $month   the month, default is current local month
  1069.      * @param int    $year    the year in four digit format, default is current local year
  1070.      * @param string $format  the string indicating how to format the output
  1071.      *
  1072.      * @return string  the date in the desired format
  1073.      *
  1074.      * @access public
  1075.      * @static
  1076.      */
  1077.     function nextWeekday($day = 0, $month = 0, $year = 0,
  1078.                          $format = DATE_CALC_FORMAT)
  1079.     {
  1080.         if (empty($year)) {
  1081.             $year = Date_Calc::dateNow('%Y');
  1082.         }
  1083.         if (empty($month)) {
  1084.             $month = Date_Calc::dateNow('%m');
  1085.         }
  1086.         if (empty($day)) {
  1087.             $day = Date_Calc::dateNow('%d');
  1088.         }
  1089.         $days = Date_Calc::dateToDays($day, $month, $year);
  1090.         if (Date_Calc::dayOfWeek($day, $month, $year) == 5) {
  1091.             $days += 3;
  1092.         } elseif (Date_Calc::dayOfWeek($day, $month, $year) == 6) {
  1093.             $days += 2;
  1094.         } else {
  1095.             $days += 1;
  1096.         }
  1097.         return Date_Calc::daysToDate($days, $format);
  1098.     }
  1099.  
  1100.     /**
  1101.      * Returns date of the previous specific day of the week
  1102.      * from the given date
  1103.      *
  1104.      * @param int day of week, 0=Sunday
  1105.      * @param int    $day     the day of the month, default is current local day
  1106.      * @param int    $month   the month, default is current local month
  1107.      * @param int    $year    the year in four digit format, default is current local year
  1108.      * @param bool   $onOrBefore  if true and days are same, returns current day
  1109.      * @param string $format  the string indicating how to format the output
  1110.      *
  1111.      * @return string  the date in the desired format
  1112.      *
  1113.      * @access public
  1114.      * @static
  1115.      */
  1116.     function prevDayOfWeek($dow, $day = 0, $month = 0, $year = 0,
  1117.                            $format = DATE_CALC_FORMAT, $onOrBefore = false)
  1118.     {
  1119.         if (empty($year)) {
  1120.             $year = Date_Calc::dateNow('%Y');
  1121.         }
  1122.         if (empty($month)) {
  1123.             $month = Date_Calc::dateNow('%m');
  1124.         }
  1125.         if (empty($day)) {
  1126.             $day = Date_Calc::dateNow('%d');
  1127.         }
  1128.         $days = Date_Calc::dateToDays($day, $month, $year);
  1129.         $curr_weekday = Date_Calc::dayOfWeek($day, $month, $year);
  1130.         if ($curr_weekday == $dow) {
  1131.             if (!$onOrBefore) {
  1132.                 $days -= 7;
  1133.             }
  1134.         } elseif ($curr_weekday < $dow) {
  1135.             $days -= 7 - ($dow - $curr_weekday);
  1136.         } else {
  1137.             $days -= $curr_weekday - $dow;
  1138.         }
  1139.         return Date_Calc::daysToDate($days, $format);
  1140.     }
  1141.  
  1142.     /**
  1143.      * Returns date of the next specific day of the week
  1144.      * from the given date
  1145.      *
  1146.      * @param int    $dow     the day of the week (0 = Sunday)
  1147.      * @param int    $day     the day of the month, default is current local day
  1148.      * @param int    $month   the month, default is current local month
  1149.      * @param int    $year    the year in four digit format, default is current local year
  1150.      * @param bool   $onOrAfter  if true and days are same, returns current day
  1151.      * @param string $format  the string indicating how to format the output
  1152.      *
  1153.      * @return string  the date in the desired format
  1154.      *
  1155.      * @access public
  1156.      * @static
  1157.      */
  1158.     function nextDayOfWeek($dow, $day = 0, $month = 0, $year = 0,
  1159.                            $format = DATE_CALC_FORMAT, $onOrAfter = false)
  1160.     {
  1161.         if (empty($year)) {
  1162.             $year = Date_Calc::dateNow('%Y');
  1163.         }
  1164.         if (empty($month)) {
  1165.             $month = Date_Calc::dateNow('%m');
  1166.         }
  1167.         if (empty($day)) {
  1168.             $day = Date_Calc::dateNow('%d');
  1169.         }
  1170.  
  1171.         $days = Date_Calc::dateToDays($day, $month, $year);
  1172.         $curr_weekday = Date_Calc::dayOfWeek($day, $month, $year);
  1173.  
  1174.         if ($curr_weekday == $dow) {
  1175.             if (!$onOrAfter) {
  1176.                 $days += 7;
  1177.             }
  1178.         } elseif ($curr_weekday > $dow) {
  1179.             $days += 7 - ($curr_weekday - $dow);
  1180.         } else {
  1181.             $days += $dow - $curr_weekday;
  1182.         }
  1183.  
  1184.         return Date_Calc::daysToDate($days, $format);
  1185.     }
  1186.  
  1187.     /**
  1188.      * Returns date of the previous specific day of the week
  1189.      * on or before the given date
  1190.      *
  1191.      * @param int    $dow     the day of the week (0 = Sunday)
  1192.      * @param int    $day     the day of the month, default is current local day
  1193.      * @param int    $month   the month, default is current local month
  1194.      * @param int    $year    the year in four digit format, default is current local year
  1195.      * @param string $format  the string indicating how to format the output
  1196.      *
  1197.      * @return string  the date in the desired format
  1198.      *
  1199.      * @access public
  1200.      * @static
  1201.      */
  1202.     function prevDayOfWeekOnOrBefore($dow, $day = 0, $month = 0, $year = 0,
  1203.                                      $format = DATE_CALC_FORMAT)
  1204.     {
  1205.         return Date_Calc::prevDayOfWeek($dow, $day, $month, $year, $format,
  1206.                                         true);
  1207.     }
  1208.  
  1209.     /**
  1210.      * Returns date of the next specific day of the week
  1211.      * on or after the given date
  1212.      *
  1213.      * @param int    $dow     the day of the week (0 = Sunday)
  1214.      * @param int    $day     the day of the month, default is current local day
  1215.      * @param int    $month   the month, default is current local month
  1216.      * @param int    $year    the year in four digit format, default is current local year
  1217.      * @param string $format  the string indicating how to format the output
  1218.      *
  1219.      * @return string  the date in the desired format
  1220.      *
  1221.      * @access public
  1222.      * @static
  1223.      */
  1224.     function nextDayOfWeekOnOrAfter($dow, $day = 0, $month = 0, $year = 0,
  1225.                                     $format = DATE_CALC_FORMAT)
  1226.     {
  1227.         return Date_Calc::nextDayOfWeek($dow, $day, $month, $year, $format,
  1228.                                         true);
  1229.     }
  1230.  
  1231.     /**
  1232.      * Find the month day of the beginning of week for given date,
  1233.      * using DATE_CALC_BEGIN_WEEKDAY
  1234.      *
  1235.      * Can return weekday of prev month.
  1236.      *
  1237.      * @param int    $day     the day of the month, default is current local day
  1238.      * @param int    $month   the month, default is current local month
  1239.      * @param int    $year    the year in four digit format, default is current local year
  1240.      * @param string $format  the string indicating how to format the output
  1241.      *
  1242.      * @return string  the date in the desired format
  1243.      *
  1244.      * @access public
  1245.      * @static
  1246.      */
  1247.     function beginOfWeek($day = 0, $month = 0, $year = 0,
  1248.                          $format = DATE_CALC_FORMAT)
  1249.     {
  1250.         if (empty($year)) {
  1251.             $year = Date_Calc::dateNow('%Y');
  1252.         }
  1253.         if (empty($month)) {
  1254.             $month = Date_Calc::dateNow('%m');
  1255.         }
  1256.         if (empty($day)) {
  1257.             $day = Date_Calc::dateNow('%d');
  1258.         }
  1259.         $this_weekday = Date_Calc::dayOfWeek($day, $month, $year);
  1260.         $interval = (7 - DATE_CALC_BEGIN_WEEKDAY + $this_weekday) % 7;
  1261.         return Date_Calc::daysToDate(Date_Calc::dateToDays($day, $month, $year)
  1262.                                      - $interval, $format);
  1263.     }
  1264.  
  1265.     /**
  1266.      * Find the month day of the end of week for given date,
  1267.      * using DATE_CALC_BEGIN_WEEKDAY
  1268.      *
  1269.      * Can return weekday of following month.
  1270.      *
  1271.      * @param int    $day     the day of the month, default is current local day
  1272.      * @param int    $month   the month, default is current local month
  1273.      * @param int    $year    the year in four digit format, default is current local year
  1274.      * @param string $format  the string indicating how to format the output
  1275.      *
  1276.      * @return string  the date in the desired format
  1277.      *
  1278.      * @access public
  1279.      * @static
  1280.      */
  1281.     function endOfWeek($day = 0, $month = 0, $year = 0,
  1282.                        $format = DATE_CALC_FORMAT)
  1283.     {
  1284.         if (empty($year)) {
  1285.             $year = Date_Calc::dateNow('%Y');
  1286.         }
  1287.         if (empty($month)) {
  1288.             $month = Date_Calc::dateNow('%m');
  1289.         }
  1290.         if (empty($day)) {
  1291.             $day = Date_Calc::dateNow('%d');
  1292.         }
  1293.         $this_weekday = Date_Calc::dayOfWeek($day, $month, $year);
  1294.         $interval = (6 + DATE_CALC_BEGIN_WEEKDAY - $this_weekday) % 7;
  1295.         return Date_Calc::daysToDate(Date_Calc::dateToDays($day, $month, $year)
  1296.                                      + $interval, $format);
  1297.     }
  1298.  
  1299.     /**
  1300.      * Find the month day of the beginning of week before given date,
  1301.      * using DATE_CALC_BEGIN_WEEKDAY
  1302.      *
  1303.      * Can return weekday of prev month.
  1304.      *
  1305.      * @param int    $day     the day of the month, default is current local day
  1306.      * @param int    $month   the month, default is current local month
  1307.      * @param int    $year    the year in four digit format, default is current local year
  1308.      * @param string $format  the string indicating how to format the output
  1309.      *
  1310.      * @return string  the date in the desired format
  1311.      *
  1312.      * @access public
  1313.      * @static
  1314.      */
  1315.     function beginOfPrevWeek($day = 0, $month = 0, $year = 0,
  1316.                              $format = DATE_CALC_FORMAT)
  1317.     {
  1318.         if (empty($year)) {
  1319.             $year = Date_Calc::dateNow('%Y');
  1320.         }
  1321.         if (empty($month)) {
  1322.             $month = Date_Calc::dateNow('%m');
  1323.         }
  1324.         if (empty($day)) {
  1325.             $day = Date_Calc::dateNow('%d');
  1326.         }
  1327.  
  1328.         $date = Date_Calc::daysToDate(Date_Calc::dateToDays($day-7,
  1329.                                                             $month,
  1330.                                                             $year),
  1331.                                       '%Y%m%d');
  1332.  
  1333.         $prev_week_year  = substr($date, 0, 4);
  1334.         $prev_week_month = substr($date, 4, 2);
  1335.         $prev_week_day   = substr($date, 6, 2);
  1336.  
  1337.         return Date_Calc::beginOfWeek($prev_week_day, $prev_week_month,
  1338.                                       $prev_week_year, $format);
  1339.     }
  1340.  
  1341.     /**
  1342.      * Find the month day of the beginning of week after given date,
  1343.      * using DATE_CALC_BEGIN_WEEKDAY
  1344.      *
  1345.      * Can return weekday of prev month.
  1346.      *
  1347.      * @param int    $day     the day of the month, default is current local day
  1348.      * @param int    $month   the month, default is current local month
  1349.      * @param int    $year    the year in four digit format, default is current local year
  1350.      * @param string $format  the string indicating how to format the output
  1351.      *
  1352.      * @return string  the date in the desired format
  1353.      *
  1354.      * @access public
  1355.      * @static
  1356.      */
  1357.     function beginOfNextWeek($day = 0, $month = 0, $year = 0,
  1358.                              $format = DATE_CALC_FORMAT)
  1359.     {
  1360.         if (empty($year)) {
  1361.             $year = Date_Calc::dateNow('%Y');
  1362.         }
  1363.         if (empty($month)) {
  1364.             $month = Date_Calc::dateNow('%m');
  1365.         }
  1366.         if (empty($day)) {
  1367.             $day = Date_Calc::dateNow('%d');
  1368.         }
  1369.  
  1370.         $date = Date_Calc::daysToDate(Date_Calc::dateToDays($day + 7,
  1371.                                                             $month,
  1372.                                                             $year),
  1373.                                       '%Y%m%d');
  1374.  
  1375.         $next_week_year  = substr($date, 0, 4);
  1376.         $next_week_month = substr($date, 4, 2);
  1377.         $next_week_day   = substr($date, 6, 2);
  1378.  
  1379.         return Date_Calc::beginOfWeek($next_week_day, $next_week_month,
  1380.                                       $next_week_year, $format);
  1381.     }
  1382.  
  1383.     /**
  1384.      * Return date of first day of month of given date
  1385.      *
  1386.      * @param int    $month   the month, default is current local month
  1387.      * @param int    $year    the year in four digit format, default is current local year
  1388.      * @param string $format  the string indicating how to format the output
  1389.      *
  1390.      * @return string  the date in the desired format
  1391.      *
  1392.      * @access public
  1393.      * @static
  1394.      * @see Date_Calc::beginOfMonthBySpan()
  1395.      * @deprecated Method deprecated in Release 1.5.0
  1396.      */
  1397.     function beginOfMonth($month = 0, $year = 0, $format = DATE_CALC_FORMAT)
  1398.     {
  1399.         if (empty($year)) {
  1400.             $year = Date_Calc::dateNow('%Y');
  1401.         }
  1402.         if (empty($month)) {
  1403.             $month = Date_Calc::dateNow('%m');
  1404.         }
  1405.         return Date_Calc::dateFormat('01', $month, $year, $format);
  1406.     }
  1407.  
  1408.     /**
  1409.      * Returns date of the first day of previous month of given date
  1410.      *
  1411.      * @param int    $day     the day of the month, default is current local day
  1412.      * @param int    $month   the month, default is current local month
  1413.      * @param int    $year    the year in four digit format, default is current local year
  1414.      * @param string $format  the string indicating how to format the output
  1415.      *
  1416.      * @return string  the date in the desired format
  1417.      *
  1418.      * @access public
  1419.      * @static
  1420.      * @see Date_Calc::beginOfMonthBySpan()
  1421.      * @deprecated Method deprecated in Release 1.5.0
  1422.      */
  1423.     function beginOfPrevMonth($day = 0, $month = 0, $year = 0,
  1424.                               $format = DATE_CALC_FORMAT)
  1425.     {
  1426.         if (empty($year)) {
  1427.             $year = Date_Calc::dateNow('%Y');
  1428.         }
  1429.         if (empty($month)) {
  1430.             $month = Date_Calc::dateNow('%m');
  1431.         }
  1432.         if (empty($day)) {
  1433.             $day = Date_Calc::dateNow('%d');
  1434.         }
  1435.         if ($month > 1) {
  1436.             $month--;
  1437.             $day = 1;
  1438.         } else {
  1439.             $year--;
  1440.             $month = 12;
  1441.             $day   = 1;
  1442.         }
  1443.         return Date_Calc::dateFormat($day, $month, $year, $format);
  1444.     }
  1445.  
  1446.     /**
  1447.      * Returns date of the last day of previous month for given date
  1448.      *
  1449.      * @param int    $day     the day of the month, default is current local day
  1450.      * @param int    $month   the month, default is current local month
  1451.      * @param int    $year    the year in four digit format, default is current local year
  1452.      * @param string $format  the string indicating how to format the output
  1453.      *
  1454.      * @return string  the date in the desired format
  1455.      *
  1456.      * @access public
  1457.      * @static
  1458.      * @see Date_Calc::endOfMonthBySpan()
  1459.      * @deprecated Method deprecated in Release 1.5.0
  1460.      */
  1461.     function endOfPrevMonth($day = 0, $month = 0, $year = 0,
  1462.                             $format = DATE_CALC_FORMAT)
  1463.     {
  1464.         if (empty($year)) {
  1465.             $year = Date_Calc::dateNow('%Y');
  1466.         }
  1467.         if (empty($month)) {
  1468.             $month = Date_Calc::dateNow('%m');
  1469.         }
  1470.         if (empty($day)) {
  1471.             $day = Date_Calc::dateNow('%d');
  1472.         }
  1473.         if ($month > 1) {
  1474.             $month--;
  1475.         } else {
  1476.             $year--;
  1477.             $month = 12;
  1478.         }
  1479.         $day = Date_Calc::daysInMonth($month, $year);
  1480.         return Date_Calc::dateFormat($day, $month, $year, $format);
  1481.     }
  1482.  
  1483.     /**
  1484.      * Returns date of begin of next month of given date
  1485.      *
  1486.      * @param int    $day     the day of the month, default is current local day
  1487.      * @param int    $month   the month, default is current local month
  1488.      * @param int    $year    the year in four digit format, default is current local year
  1489.      * @param string $format  the string indicating how to format the output
  1490.      *
  1491.      * @return string  the date in the desired format
  1492.      *
  1493.      * @access public
  1494.      * @static
  1495.      * @see Date_Calc::beginOfMonthBySpan()
  1496.      * @deprecated Method deprecated in Release 1.5.0
  1497.      */
  1498.     function beginOfNextMonth($day = 0, $month = 0, $year = 0,
  1499.                               $format = DATE_CALC_FORMAT)
  1500.     {
  1501.         if (empty($year)) {
  1502.             $year = Date_Calc::dateNow('%Y');
  1503.         }
  1504.         if (empty($month)) {
  1505.             $month = Date_Calc::dateNow('%m');
  1506.         }
  1507.         if (empty($day)) {
  1508.             $day = Date_Calc::dateNow('%d');
  1509.         }
  1510.         if ($month < 12) {
  1511.             $month++;
  1512.             $day = 1;
  1513.         } else {
  1514.             $year++;
  1515.             $month = 1;
  1516.             $day = 1;
  1517.         }
  1518.         return Date_Calc::dateFormat($day, $month, $year, $format);
  1519.     }
  1520.  
  1521.     /**
  1522.      * Returns date of the last day of next month of given date
  1523.      *
  1524.      * @param int    $day     the day of the month, default is current local day
  1525.      * @param int    $month   the month, default is current local month
  1526.      * @param int    $year    the year in four digit format, default is current local year
  1527.      * @param string $format  the string indicating how to format the output
  1528.      *
  1529.      * @return string  the date in the desired format
  1530.      *
  1531.      * @access public
  1532.      * @static
  1533.      * @see Date_Calc::endOfMonthBySpan()
  1534.      * @deprecated Method deprecated in Release 1.5.0
  1535.      */
  1536.     function endOfNextMonth($day = 0, $month = 0, $year = 0,
  1537.                             $format = DATE_CALC_FORMAT)
  1538.     {
  1539.         if (empty($year)) {
  1540.             $year = Date_Calc::dateNow('%Y');
  1541.         }
  1542.         if (empty($month)) {
  1543.             $month = Date_Calc::dateNow('%m');
  1544.         }
  1545.         if (empty($day)) {
  1546.             $day = Date_Calc::dateNow('%d');
  1547.         }
  1548.         if ($month < 12) {
  1549.             $month++;
  1550.         } else {
  1551.             $year++;
  1552.             $month = 1;
  1553.         }
  1554.         $day = Date_Calc::daysInMonth($month, $year);
  1555.         return Date_Calc::dateFormat($day, $month, $year, $format);
  1556.     }
  1557.  
  1558.     /**
  1559.      * Returns date of the first day of the month in the number of months
  1560.      * from the given date
  1561.      *
  1562.      * @param int    $months  the number of months from the date provided.
  1563.      *                         Positive numbers go into the future.
  1564.      *                         Negative numbers go into the past.
  1565.      *                         0 is the month presented in $month.
  1566.      * @param string $month   the month, default is current local month
  1567.      * @param string $year    the year in four digit format, default is the
  1568.      *                         current local year
  1569.      * @param string $format  the string indicating how to format the output
  1570.      *
  1571.      * @return string  the date in the desired format
  1572.      *
  1573.      * @access public
  1574.      * @static
  1575.      * @since  Method available since Release 1.5.0
  1576.      */
  1577.     function beginOfMonthBySpan($months = 0, $month = 0, $year = 0,
  1578.                                 $format = DATE_CALC_FORMAT)
  1579.     {
  1580.         if (empty($year)) {
  1581.             $year = Date_Calc::dateNow('%Y');
  1582.         }
  1583.         if (empty($month)) {
  1584.             $month = Date_Calc::dateNow('%m');
  1585.         }
  1586.         if ($months > 0) {
  1587.             // future month
  1588.             $tmp_mo = $month + $months;
  1589.             $month  = $tmp_mo % 12;
  1590.             if ($month == 0) {
  1591.                 $month = 12;
  1592.                 $year = $year + floor(($tmp_mo - 1) / 12);
  1593.             } else {
  1594.                 $year = $year + floor($tmp_mo / 12);
  1595.             }
  1596.         } else {
  1597.             // past or present month
  1598.             $tmp_mo = $month + $months;
  1599.             if ($tmp_mo > 0) {
  1600.                 // same year
  1601.                 $month = $tmp_mo;
  1602.             } elseif ($tmp_mo == 0) {
  1603.                 // prior dec
  1604.                 $month = 12;
  1605.                 $year--;
  1606.             } else {
  1607.                 // some time in a prior year
  1608.                 $month = 12 + ($tmp_mo % 12);
  1609.                 $year  = $year + floor($tmp_mo / 12);
  1610.             }
  1611.         }
  1612.         return Date_Calc::dateFormat(1, $month, $year, $format);
  1613.     }
  1614.  
  1615.     /**
  1616.      * Returns date of the last day of the month in the number of months
  1617.      * from the given date
  1618.      *
  1619.      * @param int    $months  the number of months from the date provided.
  1620.      *                         Positive numbers go into the future.
  1621.      *                         Negative numbers go into the past.
  1622.      *                         0 is the month presented in $month.
  1623.      * @param string $month   the month, default is current local month
  1624.      * @param string $year    the year in four digit format, default is the
  1625.      *                         current local year
  1626.      * @param string $format  the string indicating how to format the output
  1627.      *
  1628.      * @return string  the date in the desired format
  1629.      *
  1630.      * @access public
  1631.      * @static
  1632.      * @since  Method available since Release 1.5.0
  1633.      */
  1634.     function endOfMonthBySpan($months = 0, $month = 0, $year = 0,
  1635.                               $format = DATE_CALC_FORMAT)
  1636.     {
  1637.         if (empty($year)) {
  1638.             $year = Date_Calc::dateNow('%Y');
  1639.         }
  1640.         if (empty($month)) {
  1641.             $month = Date_Calc::dateNow('%m');
  1642.         }
  1643.         if ($months > 0) {
  1644.             // future month
  1645.             $tmp_mo = $month + $months;
  1646.             $month  = $tmp_mo % 12;
  1647.             if ($month == 0) {
  1648.                 $month = 12;
  1649.                 $year = $year + floor(($tmp_mo - 1) / 12);
  1650.             } else {
  1651.                 $year = $year + floor($tmp_mo / 12);
  1652.             }
  1653.         } else {
  1654.             // past or present month
  1655.             $tmp_mo = $month + $months;
  1656.             if ($tmp_mo > 0) {
  1657.                 // same year
  1658.                 $month = $tmp_mo;
  1659.             } elseif ($tmp_mo == 0) {
  1660.                 // prior dec
  1661.                 $month = 12;
  1662.                 $year--;
  1663.             } else {
  1664.                 // some time in a prior year
  1665.                 $month = 12 + ($tmp_mo % 12);
  1666.                 $year  = $year + floor($tmp_mo / 12);
  1667.             }
  1668.         }
  1669.         return Date_Calc::dateFormat(Date_Calc::daysInMonth($month, $year),
  1670.                                      $month, $year, $format);
  1671.     }
  1672.  
  1673.     /**
  1674.      * Find the day of the week for the first of the month of given date
  1675.      *
  1676.      * @param int    $month   the month, default is current local month
  1677.      * @param int    $year    the year in four digit format, default is current local year
  1678.      *
  1679.      * @return int number of weekday for the first day, 0=Sunday
  1680.      *
  1681.      * @access public
  1682.      * @static
  1683.      */
  1684.     function firstOfMonthWeekday($month = 0, $year = 0)
  1685.     {
  1686.         if (empty($year)) {
  1687.             $year = Date_Calc::dateNow('%Y');
  1688.         }
  1689.         if (empty($month)) {
  1690.             $month = Date_Calc::dateNow('%m');
  1691.         }
  1692.         return Date_Calc::dayOfWeek('01', $month, $year);
  1693.     }
  1694.  
  1695.     /**
  1696.      * Calculates the date of the Nth weekday of the month,
  1697.      * such as the second Saturday of January 2000
  1698.      *
  1699.      * @param int    $week    the number of the week to get
  1700.      *                         (1 = first, etc.  Also can be 'last'.)
  1701.      * @param int    $dow     the day of the week (0 = Sunday)
  1702.      * @param int    $month   the month
  1703.      * @param int    $year    the year.  Use the complete year instead of the
  1704.      *                         abbreviated version.  E.g. use 2005, not 05.
  1705.      *                         Do not add leading 0's for years prior to 1000.
  1706.      * @param string $format  the string indicating how to format the output
  1707.      *
  1708.      * @return string  the date in the desired format
  1709.      *
  1710.      * @access public
  1711.      * @static
  1712.      */
  1713.     function NWeekdayOfMonth($week, $dow, $month, $year,
  1714.                              $format = DATE_CALC_FORMAT)
  1715.     {
  1716.         if (is_numeric($week)) {
  1717.             $DOW1day = ($week - 1) * 7 + 1;
  1718.             $DOW1    = Date_Calc::dayOfWeek($DOW1day, $month, $year);
  1719.             $wdate   = ($week - 1) * 7 + 1 + (7 + $dow - $DOW1) % 7;
  1720.             if ($wdate > Date_Calc::daysInMonth($month, $year)) {
  1721.                 return -1;
  1722.             } else {
  1723.                 return Date_Calc::dateFormat($wdate, $month, $year, $format);
  1724.             }
  1725.         } elseif ($week == 'last' && $dow < 7) {
  1726.             $lastday = Date_Calc::daysInMonth($month, $year);
  1727.             $lastdow = Date_Calc::dayOfWeek($lastday, $month, $year);
  1728.             $diff    = $dow - $lastdow;
  1729.             if ($diff > 0) {
  1730.                 return Date_Calc::dateFormat($lastday - (7 - $diff), $month,
  1731.                                              $year, $format);
  1732.             } else {
  1733.                 return Date_Calc::dateFormat($lastday + $diff, $month,
  1734.                                              $year, $format);
  1735.             }
  1736.         } else {
  1737.             return -1;
  1738.         }
  1739.     }
  1740.  
  1741.     /**
  1742.      * Returns true for valid date, false for invalid date
  1743.      *
  1744.      * @param int    $day     the day of the month
  1745.      * @param int    $month   the month
  1746.      * @param int    $year    the year.  Use the complete year instead of the
  1747.      *                         abbreviated version.  E.g. use 2005, not 05.
  1748.      *                         Do not add leading 0's for years prior to 1000.
  1749.      *
  1750.      * @return boolean
  1751.      *
  1752.      * @access public
  1753.      * @static
  1754.      */
  1755.     function isValidDate($day, $month, $year)
  1756.     {
  1757.         if ($year < 0 || $year > 9999) {
  1758.             return false;
  1759.         }
  1760.         if (!checkdate($month, $day, $year)) {
  1761.             return false;
  1762.         }
  1763.         return true;
  1764.     }
  1765.  
  1766.     /**
  1767.      * Returns true for a leap year, else false
  1768.      *
  1769.      * @param int    $year    the year.  Use the complete year instead of the
  1770.      *                         abbreviated version.  E.g. use 2005, not 05.
  1771.      *                         Do not add leading 0's for years prior to 1000.
  1772.      *
  1773.      * @return boolean
  1774.      *
  1775.      * @access public
  1776.      * @static
  1777.      */
  1778.     function isLeapYear($year = 0)
  1779.     {
  1780.         if (empty($year)) {
  1781.             $year = Date_Calc::dateNow('%Y');
  1782.         }
  1783.         if (preg_match('/\D/', $year)) {
  1784.             return false;
  1785.         }
  1786.         if ($year < 1000) {
  1787.             return false;
  1788.         }
  1789.         if ($year < 1582) {
  1790.             // pre Gregorio XIII - 1582
  1791.             return ($year % 4 == 0);
  1792.         } else {
  1793.             // post Gregorio XIII - 1582
  1794.             return (($year % 4 == 0) && ($year % 100 != 0)) || ($year % 400 == 0);
  1795.         }
  1796.     }
  1797.  
  1798.     /**
  1799.      * Determines if given date is a future date from now
  1800.      *
  1801.      * @param int    $day     the day of the month
  1802.      * @param int    $month   the month
  1803.      * @param int    $year    the year.  Use the complete year instead of the
  1804.      *                         abbreviated version.  E.g. use 2005, not 05.
  1805.      *                         Do not add leading 0's for years prior to 1000.
  1806.      *
  1807.      * @return boolean
  1808.      *
  1809.      * @access public
  1810.      * @static
  1811.      */
  1812.     function isFutureDate($day, $month, $year)
  1813.     {
  1814.         $this_year  = Date_Calc::dateNow('%Y');
  1815.         $this_month = Date_Calc::dateNow('%m');
  1816.         $this_day   = Date_Calc::dateNow('%d');
  1817.  
  1818.         if ($year > $this_year) {
  1819.             return true;
  1820.         } elseif ($year == $this_year) {
  1821.             if ($month > $this_month) {
  1822.                 return true;
  1823.             } elseif ($month == $this_month) {
  1824.                 if ($day > $this_day) {
  1825.                     return true;
  1826.                 }
  1827.             }
  1828.         }
  1829.         return false;
  1830.     }
  1831.  
  1832.     /**
  1833.      * Determines if given date is a past date from now
  1834.      *
  1835.      * @param int    $day     the day of the month
  1836.      * @param int    $month   the month
  1837.      * @param int    $year    the year.  Use the complete year instead of the
  1838.      *                         abbreviated version.  E.g. use 2005, not 05.
  1839.      *                         Do not add leading 0's for years prior to 1000.
  1840.      *
  1841.      * @return boolean
  1842.      *
  1843.      * @access public
  1844.      * @static
  1845.      */
  1846.     function isPastDate($day, $month, $year)
  1847.     {
  1848.         $this_year  = Date_Calc::dateNow('%Y');
  1849.         $this_month = Date_Calc::dateNow('%m');
  1850.         $this_day   = Date_Calc::dateNow('%d');
  1851.  
  1852.         if ($year < $this_year) {
  1853.             return true;
  1854.         } elseif ($year == $this_year) {
  1855.             if ($month < $this_month) {
  1856.                 return true;
  1857.             } elseif ($month == $this_month) {
  1858.                 if ($day < $this_day) {
  1859.                     return true;
  1860.                 }
  1861.             }
  1862.         }
  1863.         return false;
  1864.     }
  1865.  
  1866.     /**
  1867.      * Returns number of days between two given dates
  1868.      *
  1869.      * @param int    $day1    the day of the month
  1870.      * @param int    $month1  the month
  1871.      * @param int    $year1   the year.  Use the complete year instead of the
  1872.      *                         abbreviated version.  E.g. use 2005, not 05.
  1873.      *                         Do not add leading 0's for years prior to 1000.
  1874.      * @param int    $day2    the day of the month
  1875.      * @param int    $month2  the month
  1876.      * @param int    $year2   the year.  Use the complete year instead of the
  1877.      *                         abbreviated version.  E.g. use 2005, not 05.
  1878.      *                         Do not add leading 0's for years prior to 1000.
  1879.      *
  1880.      * @return int  the absolute number of days between the two dates.
  1881.      *               If an error occurs, -1 is returned.
  1882.      *
  1883.      * @access public
  1884.      * @static
  1885.      */
  1886.     function dateDiff($day1, $month1, $year1, $day2, $month2, $year2)
  1887.     {
  1888.         if (!Date_Calc::isValidDate($day1, $month1, $year1)) {
  1889.             return -1;
  1890.         }
  1891.         if (!Date_Calc::isValidDate($day2, $month2, $year2)) {
  1892.             return -1;
  1893.         }
  1894.         return abs(Date_Calc::dateToDays($day1, $month1, $year1)
  1895.                    - Date_Calc::dateToDays($day2, $month2, $year2));
  1896.     }
  1897.  
  1898.     /**
  1899.      * Compares two dates
  1900.      *
  1901.      * @param int    $day1    the day of the month
  1902.      * @param int    $month1  the month
  1903.      * @param int    $year1   the year.  Use the complete year instead of the
  1904.      *                         abbreviated version.  E.g. use 2005, not 05.
  1905.      *                         Do not add leading 0's for years prior to 1000.
  1906.      * @param int    $day2    the day of the month
  1907.      * @param int    $month2  the month
  1908.      * @param int    $year2   the year.  Use the complete year instead of the
  1909.      *                         abbreviated version.  E.g. use 2005, not 05.
  1910.      *                         Do not add leading 0's for years prior to 1000.
  1911.      *
  1912.      * @return int  0 if the dates are equal. 1 if date 1 is later, -1 if
  1913.      *               date 1 is earlier.
  1914.      *
  1915.      * @access public
  1916.      * @static
  1917.      */
  1918.     function compareDates($day1, $month1, $year1, $day2, $month2, $year2)
  1919.     {
  1920.         $ndays1 = Date_Calc::dateToDays($day1, $month1, $year1);
  1921.         $ndays2 = Date_Calc::dateToDays($day2, $month2, $year2);
  1922.         if ($ndays1 == $ndays2) {
  1923.             return 0;
  1924.         }
  1925.         return ($ndays1 > $ndays2) ? 1 : -1;
  1926.     }
  1927. }
  1928.  
  1929. ?>
  1930.